import { log } from './console'

/**
 * 官服 shard
 */
export const shards = ['shard0', 'shard1', 'shard2', 'shard3'] as const
export type Shard = (typeof shards)[number]

/**
 * 当前是否处于官服
 */
export const isOfficialShard = () => {
    return !!Game.cpu.generatePixel
}

/**
 * 当前是否处于赛季服
 */
export const isSeasonShard = () => {
    return Game.shard.name === 'seasonShard'
}

/**
 * 获取指定长度的 id
 */
export const generateId = (length = 10) => {
    return Math.random().toString(36).slice(-length)
}

/**
 * 判断游戏时间是否达到该间隔，用于每隔一定时间执行一次的场景
 * @param interval 间隔
 */
export const isInterval = (interval: number) => {
    return Game.time % interval === 0
}

/**
 * 如果只是单纯使用 isInterval，给定相同的时间间隔，每个房间将要在同一时间执行，这样会导致 cpu 消耗不稳定
 */
export const isRoomInterval = (room: Room, interval: number) => {
    const [x, y] = roomNameToXY(room.name)
    return (Game.time - x - y) % interval === 0
}

/**
 * 判断某房间是否是自己的
 */
export const isMyRoom = (room?: Room): room is MyRoom => {
    return !!room?.controller?.my
}

/**
 * 缓存函数，当传入的参数不变时，直接返回上一次的结果
 */
export const cached = function <T extends (...args: unknown[]) => unknown>(fn: T): T {
    const cachedMap = new Map()
    return function (this: unknown, ...args: unknown[]) {
        // null 或者 undefined 没有 toString 方法，可以包在数组里用
        const key =
            '_' +
            args
                .map((arg) => {
                    if (typeof arg === 'function') return arg.name
                    return [arg].toString()
                })
                .join(',')
        if (cachedMap.has(key)) return cachedMap.get(key)
        const result = fn.apply(this, args)
        cachedMap.set(key, result)
        return result
    } as T
}

/**
 * 对象原型拓展，比如 asignPrototype(Creep,CreepMove)
 */
export const assignPrototype = function (obj1: { [key: string]: any }, obj2: { [key: string]: any }) {
    Object.getOwnPropertyNames(obj2.prototype).forEach((key) => {
        if (key.includes('Getter')) {
            Object.defineProperty(obj1.prototype, key.split('Getter')[0], {
                get: obj2.prototype[key],
                enumerable: false,
                configurable: true,
            })
        } else obj1.prototype[key] = obj2.prototype[key]
    })
}

/**
 * 从 x，y 坐标获取房间名
 */
export const getRoomNameFromXY = cached((x: number, y: number) => {
    let we: string, ns: string
    if (x < 0) {
        we = 'W' + (-x - 1)
    } else {
        we = 'E' + x
    }
    if (y < 0) {
        ns = 'N' + (-y - 1)
    } else {
        ns = 'S' + y
    }
    return '' + we + ns
})

/**
 * 从房间名获取 x，y 坐标
 */
export const roomNameToXY = cached((name: string) => {
    let xx = parseInt(name.substr(1), 10)
    let verticalPos = 2
    if (xx >= 100) {
        verticalPos = 4
    } else if (xx >= 10) {
        verticalPos = 3
    }
    let yy = parseInt(name.substr(verticalPos + 1), 10)
    const horizontalDir = name.charAt(0)
    const verticalDir = name.charAt(verticalPos)
    if (horizontalDir === 'W' || horizontalDir === 'w') {
        xx = -xx - 1
    }
    if (verticalDir === 'N' || verticalDir === 'n') {
        yy = -yy - 1
    }
    return [xx, yy]
})

/**
 * 计算两点距离
 */
export const getRange = (x1: number, y1: number, x2: number, y2: number) =>
    Math.max(Math.abs(x1 - x2), Math.abs(y1 - y2))

/**
 * 在 global 上挂载属性
 */
export const defineGlobalProperty = (p: PropertyKey, attributes: PropertyDescriptor & ThisType<any>) => {
    try {
        Object.defineProperty(global, p, attributes)
    } catch (error) {
        log(`${p.toString()} 挂载失败`, ['全局属性'], 'red')
    }
}
